﻿using System;
using System.Text;
using System.Xml;

namespace ThresholdAssistant.Tools
{
    /// <summary>
    /// Xml节点处理工具类
    /// </summary>
    public static class XmlNodeUtil
    {
        /// <summary>
        /// 修改node子节点tagname的文本
        /// </summary>
        /// <param name="node"></param>
        /// <param name="tagName"></param>
        /// <param name="newText"></param>
        public static void UpdateXmlNodeText(this XmlNode node, string tagName, string newText)
        {
            try
            {
                if (node == null || string.IsNullOrEmpty(tagName) || string.IsNullOrEmpty(newText))
                {
                    return;
                }

                XmlNode childNode = node.SelectSingleNode(tagName);
                if (childNode != null)
                {
                    childNode.InnerText = newText;
                }
            }
            catch { }
        }

        /// <summary>
        /// 获取消息内容
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        public static string FixXmlString(this string xml)
        {
            StringBuilder builder = new StringBuilder();
            bool cdata_flag = false;
            char[] chars = xml.ToCharArray();
            for (int i = 0; i < chars.Length; i++)
            {
                char c = chars[i];
                string next_c = "";
                if (i + 1 < chars.Length)
                {
                    next_c = chars[i + 1].ToString();
                }

                // 识别 <![CDATA[ 开始和 ]]> 结束，在<前没有结束，补上]]>
                if (c == '<' || c == ']')
                {
                    if (FindWordAtCharArray(chars, i, true, "<![CDATA["))
                    {
                        cdata_flag = true;
                    }
                    else if (cdata_flag == true && c == '<')
                    {
                        builder.Append("]]>");
                        cdata_flag = false;
                    }
                    else if (FindWordAtCharArray(chars, i, true, "]]>"))
                    {
                        cdata_flag = false;
                    }
                }

                // 非&直接追加
                if (c != '&')
                {
                    AppendXmlChar(builder, c, next_c, ref i);
                }
                else
                {
                    if (cdata_flag)
                    {
                        // &号 在<![CDATA[ 中允许出现
                        AppendXmlChar(builder, c, next_c, ref i);
                    }
                    else
                    {
                        // & 号，允许出现 &nbsp; &#160; &lt; &#60; &gt; &#62; &amp; &#38; &quot; &#34; &apos; &#39; &times; &#215; &divde; &#247;
                        if (FindWordAtCharArray(chars, i, true, "&nbsp;", "&#160;", "&lt;", "&#60;", "&gt;", "&#62;", "&amp;", "&#38;", " &quot;", "&#34;", "&apos;", "&#39;", "&times;", "&#215;", "&divde;", "&#247;"))
                        {
                            AppendXmlChar(builder, c, next_c, ref i);
                        }
                        else
                        {
                            builder.Append("&amp;");
                        }
                    }
                }
            }
            return builder.ToString();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="c"></param>
        /// <param name="next_c"></param>
        /// <param name="i"></param>
        private static void AppendXmlChar(StringBuilder builder, char c, string next_c, ref int i)
        {
            if ((c == 0x9) || (c == 0xA) || (c == 0xD)
                        || ((c >= 0x20) && (c <= 0xD7FF))
                        || ((c >= 0xE000) && (c <= 0xFFFD))
                        || ((c >= 0x10000) && (c <= 0x10FFFF)))
            {
                builder.Append(c.ToString());
            }
            else
            {
                if (ConvertEmoji2Int(c + next_c) > 0)
                {
                    builder.Append(c + next_c);
                    i++;
                }
                else
                {
                    builder.Append("\\u" + Convert.ToInt32(c).ToString("x2").PadLeft(4, '0'));
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="emoji"></param>
        /// <returns></returns>
        private static int ConvertEmoji2Int(string emoji)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(emoji))
                {
                    return -1;
                }
                byte[] bytes = Encoding.UTF8.GetBytes(emoji);
                string firstItem = Convert.ToString(bytes[0], 2); //获取首字节bai二进制
                if (bytes.Length != 4)
                {
                    return -1;
                }

                int iv;
                if (bytes.Length == 1)
                {
                    //单字节字符
                    iv = Convert.ToInt32(firstItem, 2);
                }
                else
                {
                    //多字节字符
                    StringBuilder sbBinary = new StringBuilder();
                    sbBinary.Append(firstItem.Substring(bytes.Length + 1).TrimStart('0'));
                    for (int i = 1; i < bytes.Length; i++)
                    {
                        string item = Convert.ToString(bytes[i], 2);
                        item = item.Substring(2);
                        sbBinary.Append(item);
                    }
                    iv = Convert.ToInt32(sbBinary.ToString(), 2);
                    if (iv >= 0x1F000 && iv <= 0x1F9C0)
                    {
                        return iv;
                    }
                    else
                    {
                        return -1;
                    }
                }
                return iv;
            }
            catch (Exception)
            {
                return -1;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="chars"></param>
        /// <param name="index"></param>
        /// <param name="ignoreCase"></param>
        /// <param name="words"></param>
        /// <returns></returns>
        private static bool FindWordAtCharArray(char[] chars, int index, bool ignoreCase, params string[] words)
        {
            for (int i = 0; i < words.Length; i++)
            {
                string word = words[i];
                if (index + word.Length > chars.Length) 
                    continue;

                string cword = "";
                for (int j = index; j < index + word.Length; j++)
                {
                    cword += chars[j].ToString();
                }
                if (ignoreCase)
                {
                    if (word.ToLower() == cword.ToLower())
                    {
                        return true;
                    }
                }
                else
                {
                    if (word == cword)
                    {
                        return true;
                    }
                }
            }
            return false;
        }
    }
}